package com.brillilab.service.logic.team;

import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.common.utils.MyBeanUtils;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.common.IsDeleteEnum;
import com.brillilab.domain.enums.lab.UserEnum;
import com.brillilab.domain.enums.team.IsLeaderEnum;
import com.brillilab.domain.enums.team.TeamMemberStateEnum;
import com.brillilab.domain.pa.team.TeamPa;
import com.brillilab.domain.po.lab.Lab;
import com.brillilab.domain.po.lab.LabMember;
import com.brillilab.domain.po.system.Dict;
import com.brillilab.domain.po.team.Team;
import com.brillilab.domain.po.team.TeamMember;
import com.brillilab.domain.po.user.Users;
import com.brillilab.domain.vo.lab.LabMemberInfo;
import com.brillilab.domain.vo.lab.LabMemberVo;
import com.brillilab.domain.vo.team.TeamDetail;
import com.brillilab.domain.vo.team.TeamInfoVo;
import com.brillilab.domain.vo.team.TeamMemberVo;
import com.brillilab.domain.vo.team.TeamVo;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.lab.ILabService;
import com.brillilab.service.core.system.IDictService;
import com.brillilab.service.core.team.ITeamMemberService;
import com.brillilab.service.core.team.ITeamService;
import com.brillilab.service.core.user.IUsersService;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 研究团队
 *
 * @author WuMenghao XuZuE
 */
@Service
@Transactional
public class TeamLogic {

    @Resource
    private ILabService labService;
    @Resource
    private ITeamService teamService;
    @Resource
    private ITeamMemberService teamMemberService;
    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private IDictService dictService;
    @Resource
    private IUsersService usersService;

    /**
     * 创建团队
     *
     * @param teamPa
     * @param labId
     * @return
     * @auth WuMengHao
     */
    public boolean createNewTeam(TeamPa teamPa,Long labId) {
        Assert.isTrue(teamPa != null && teamPa.getLeaderId() != null && StringUtils.isNotBlank(teamPa.getName()),"参数缺失！");
        Assert.isTrue(teamPa.getName().length() <= 15,"请将小组名称限制在15字以内！");
        //查重
        Team exist=teamService.selectOneByLeaderId(teamPa.getLeaderId());
        Assert.isTrue(exist == null,"团队已存在！");

        //TODO PI不能为小组成员
        Assert.isTrue(!labMemberService.isOwner(labId,teamPa.getLeaderId()),"PI已存在小组！");

        //插人team
        Team team=new Team();
        team.setLeaderId(teamPa.getLeaderId());
        team.setLabId(labId);
        team.setName(teamPa.getName());
        Assert.isTrue(teamService.insert(team),"业务操作失败！");

        //校验成员已在其他Team
        validateTeamMemberInOtherTeam(teamPa,labId);

        //插入teamMember
        List<Long> memberIds=teamPa.getMemberIds();
        List<TeamMember> teamMembers=new ArrayList<>();
        if(memberIds.size() > 0){
            //成员校验
            List<LabMember> labMembers=labMemberService.selectList(memberIds);
            Assert.isTrue(labMembers != null && labMembers.size() > 0,"实验成员不存在！");
            labMembers.forEach(e -> {
                Assert.isTrue(e.getLabId().equals(labId),"成员ID:" + e.getId() + "不属于该实验室！");
            });
            teamMembers=getNewTeamMemberList(labId,team.getId(),memberIds);
        }
        //leader成员
        TeamMember leader=new TeamMember();
        leader.setTeamId(team.getId());
        leader.setLabMemberId(teamPa.getLeaderId());
        leader.setLabId(labId);
        leader.setIsLeader(IsLeaderEnum.IS.getIsLeader());
        teamMembers.add(leader);
        Assert.isTrue(teamMemberService.insertBatch(teamMembers),"业务操作失败！");
        return true;
    }

    private List<TeamMember> getNewTeamMemberList(Long labId,Long teamId,List<Long> memberIds) {
        List<TeamMember> teamMembers;
        teamMembers=memberIds.stream().map(labMemberId -> {
            TeamMember teamMember=new TeamMember();
            teamMember.setLabMemberId(labMemberId);
            teamMember.setTeamId(teamId);
            teamMember.setLabId(labId);
            teamMember.setIsLeader(IsLeaderEnum.NO.getIsLeader());
            return teamMember;
        }).collect(Collectors.toList());
        return teamMembers;
    }

    /**
     * 编辑团队
     *
     * @param teamPa
     * @param labId
     * @return
     * @auth WuMengHao
     */
    public boolean editTeam(TeamPa teamPa,Long labId) {

        Assert.isTrue(teamPa != null && teamPa.getId() != null
                && teamPa.getLeaderId() != null && StringUtils.isNotBlank(teamPa.getName()),"参数缺失！");
        Assert.isTrue(teamPa.getName().length() <= 15,"请将小组名称限制在15字以内！");

        //小组校验
        Team team=validateTeamAndMemberInfo(teamPa,labId);

        //TODO PI小组逻辑不同不做修改
        if(!labMemberService.isOwner(labId,team.getLeaderId())){

            //去重
            List<Long> memberIds=teamPa.getMemberIds().stream().filter(e -> !e.equals(teamPa.getLeaderId())).distinct().collect(Collectors.toList());
            teamPa.setMemberIds(memberIds);

            //校验成员已在其他Team
            validateTeamMemberInOtherTeam(teamPa,labId);

            //小组数据
            TeamMember leaderOld=teamMemberService.selectLeader(teamPa.getId());

            List<TeamMember> in=teamMemberService.selectListByTeamIdAndState(teamPa.getId(),TeamMemberStateEnum.IN.getState());

            List<TeamMember> out=teamMemberService.selectListByTeamIdAndState(teamPa.getId(),TeamMemberStateEnum.OUT.getState());

            //用于的列表
            List<TeamMember> insert = new ArrayList<>();
            List<TeamMember> update = new ArrayList<>();

            //队长处理
            Long leaderId=teamPa.getLeaderId();
            Long teamId=team.getId();
            if(!leaderId.equals(leaderOld.getLabMemberId())){
                //非PI小组
                if(in.stream().anyMatch(e -> e.getLabMemberId().equals(leaderId))){
                    //是成员 in状态
                    for (TeamMember e:in){
                        if(e.getLabMemberId().equals(leaderId)){
                            e.setIsLeader(BoolEnum.TRUE.getValue());
                        }
                    }
                }else if(out.stream().anyMatch(e -> e.getLabMemberId().equals(leaderId))){
                    //是成员 out状态

                    for (TeamMember e:out){
                        if(e.getLabMemberId().equals(leaderId)){
                            e.setIsLeader(BoolEnum.TRUE.getValue());
                            e.setState(TeamMemberStateEnum.IN.getState());
                        }
                    }
                }else{
                    //不是成员
                    TeamMember newLeader=new TeamMember();
                    newLeader.setLabMemberId(leaderId);
                    newLeader.setTeamId(teamId);
                    newLeader.setLabId(labId);
                    newLeader.setIsLeader(BoolEnum.TRUE.getValue());
                    insert.add(newLeader);
                }

                for (TeamMember e:in){
                    if(e.getLabMemberId().equals(leaderOld.getLabMemberId())){
                        e.setIsLeader(BoolEnum.FALSE.getValue());
                    }
                }
            }

            //成员的处理
            in.forEach( inm -> {
                if(inm.getIsLeader().equals(BoolEnum.FALSE.getValue())){
                    if(memberIds.contains(inm.getLabMemberId())){
                        memberIds.remove(inm.getLabMemberId());
                    }else {
                        inm.setState(TeamMemberStateEnum.OUT.getState());
                    }
                }
            });
            out.forEach(onm -> {
                if(memberIds.contains(onm.getLabMemberId())){
                    onm.setState(TeamMemberStateEnum.IN.getState());
                    onm.setIsLeader(BoolEnum.FALSE.getValue());
                    memberIds.remove(onm.getLabMemberId());
                }
            });
            List<TeamMember> newMember=getNewTeamMemberList(labId,teamId,memberIds);
            insert.addAll(newMember);
            update.addAll(in);
            update.addAll(out);


            //小组处理
            if(!team.getLeaderId().equals(labId)){
                team.setLeaderId(leaderId);
            }
            if(!team.getName().equals(teamPa.getName())){
                team.setName(teamPa.getName());
            }

            //执行
            teamService.updateById(team);

            if(insert.size() > 0){
                teamMemberService.insertBatch(insert);
            }

            if(update.size() > 0){
                teamMemberService.updateBatch(update,teamId);
            }
        }else {
            //PI小组只能改名
            if(StringUtils.isNotBlank(teamPa.getName())){
                team.setName(teamPa.getName());
            }
            teamService.updateById(team);
        }

        return true;
    }

    private Team validateTeamAndMemberInfo(TeamPa teamPa,Long labId) {
        //小组校验
        Team team=teamService.selectOneByIdAndLabIdAndIsDelete(teamPa.getId(),labId,IsDeleteEnum.NO.getValue());
        Assert.notNull(team,"团队ID：" + teamPa.getId() + "不存在！");

        //组长校验
        List<Long> labMemberIds=labMemberService.selectByLabId(labId).stream().map(LabMemberVo::getLabMemberId).collect(Collectors.toList());
        Assert.isTrue(labMemberIds.contains(teamPa.getLeaderId()),"组长不是实验成员");

        //成员校验
        teamPa.getMemberIds().forEach(e -> {
            Assert.isTrue(labMemberIds.contains(e),"成员ID:" + e + "不属于该实验室！");
        });
        return team;
    }

    private void validateTeamMemberInOtherTeam(TeamPa teamPa,Long labId) {
        List<TeamMember> all=teamMemberService.selectAllTeamLabMemberId(labId)
                .stream().filter(e -> !e.getTeamId().equals(teamPa.getId())).collect(Collectors.toList());

        all.forEach(e -> {
            if( teamPa.getLeaderId().equals(e.getLabMemberId())){
                throw new BrillilabException(ResultEnum.DATA_ALREADY_EXIST,"组长已存在于其他研究小组！");
            }
            if(teamPa.getMemberIds().contains(e.getLabMemberId())){
                throw new BrillilabException(ResultEnum.DATA_ALREADY_EXIST,"成员已存在于其他研究小组！");
            }
        });
    }

    /**
     * 新增/编辑页面显示数据（未分组成员和组内成员）
     *
     * @param teamId
     * @param labId
     * @return
     * @auth WuMengHao
     */
    public TeamDetail getTeamDetail(Long teamId,Long labId) {

        Assert.notNull(labId,"参数缺失！");

        Lab lab=labService.selectById(labId);
        Assert.notNull(lab,"实验室不存在！");

        TeamDetail teamDetail=new TeamDetail();
        teamDetail.setId(teamId);
        //未分组
        List<LabMemberVo> labMembers=labMemberService.selectByLabId(labId);
        List<TeamMember> teamMembers=teamMemberService.selectListByLabIdAndState(labId,TeamMemberStateEnum.IN.getState());
        List<Long> inIdsOfLab=teamMembers.stream().map(TeamMember::getLabMemberId).collect(Collectors.toList());
        //筛选 非小组成员 非PI
        List<LabMemberVo> unGroupedMembers=labMembers.stream().filter(e -> !inIdsOfLab.contains(e.getLabMemberId()) && !e.getUserId().equals(lab.getOwnerId())).collect(Collectors.toList());
        List<TeamMemberVo> unGrouped=unGroupedMembers.stream().map(labMemberVo -> {
            TeamMemberVo teamMemberVo=new TeamMemberVo();
            teamMemberVo.setLabMemberId(labMemberVo.getLabMemberId());
            teamMemberVo.setName(labMemberVo.getUserName());
            teamMemberVo.setImageUrl(labMemberVo.getImageUrl());
            teamMemberVo.setDuty(StringUtils.isNotBlank(labMemberVo.getDuty())?labMemberVo.getDuty():"PI");
            return teamMemberVo;
        }).collect(Collectors.toList());
        teamDetail.setNoTeam(unGrouped);

        //已存在成员和leader
        if(teamId != null){
            Team team=teamService.selectOneByIdAndLabIdAndIsDelete(teamId,labId,IsDeleteEnum.NO.getValue());
            Assert.notNull(team,"团队ID：" + teamId + "不存在！");
            List<TeamMemberVo> teamMembersIn=teamMemberService.selectTeamMemberVoList(teamId,TeamMemberStateEnum.IN.getState());
            TeamMemberVo leader=teamMemberService.selectLeaderVo(teamId);
            teamDetail.setLeader(leader);
            teamDetail.setName(team.getName());
            teamDetail.setInTeam(teamMembersIn);
        }else {
            teamDetail.setInTeam(new ArrayList<>());
        }
        return teamDetail;
    }

    /**
     * 查询已分组的成员
     *
     * @param labId
     * @return
     */
    public List<TeamInfoVo> isTeam(Long labId) {

        Lab lab=labService.selectById(labId);
        Assert.notNull(lab,"实验室不存在！");

        LabMember labMember=labMemberService.selectByLabIdAndUserId(labId,lab.getOwnerId());
        Assert.notNull(labMember,"PI成员不存在！");

        Assert.isTrue(labId != null, "参数缺失！");
        List<TeamVo> teamVoList = teamService.selectTeamByLabId(labId,labMember.getUserId());
        if (!CollectionUtils.isEmpty(teamVoList)) {
            List<TeamInfoVo> teams = new ArrayList<TeamInfoVo>();
            List<Long> labMemberIdList = new LinkedList<>();
            teamVoList.forEach(t -> {
                labMemberIdList.addAll(t.getTeamMemberList().stream().map(TeamMember::getLabMemberId).collect(Collectors.toList()));
            });
            List<LabMemberInfo> labMemberInfos = teamService.selectLabMemberInfo(labMemberIdList);
            Map<Integer, String> userDutyMap = dictService.getUserDutyMap();
            for (TeamVo teamVo : teamVoList) {
                TeamInfoVo team = new TeamInfoVo();
                team.setTeamId(teamVo.getId());
                team.setTeamName(teamVo.getName());
                List<TeamMember> teamMembers = teamVo.getTeamMemberList();
                List<TeamMemberVo> teamMemberVoList = new ArrayList<>();
                for (TeamMember teamMember : teamMembers) {
                    LabMemberInfo labMemberInfo = labMemberInfos.stream().filter(m -> m.getLabMemberId().equals(teamMember.getLabMemberId())).findFirst().orElse(null);
                    if(labMemberInfo!=null) {
                        TeamMemberVo teamMemberVo = new TeamMemberVo();
                        MyBeanUtils.copyProperties(teamMember, teamMemberVo);
                        teamMemberVo.setName(labMemberInfo.getName());
                        teamMemberVo.setImageUrl(labMemberInfo.getImageUrl());
                        teamMemberVo.setDuty(StringUtils.isNotBlank(labMemberInfo.getDuty())?labMemberInfo.getDuty():"PI");
                        userDutyMap.forEach((k,v) -> {
                            if(v.equals(labMemberInfo.getDuty())){
                                teamMemberVo.setSort(k);
                            }
                        });
                        teamMemberVoList.add(teamMemberVo);
                    }
                }
                Collections.sort(teamMemberVoList, new Comparator<TeamMemberVo>() {
                    @Override
                    public int compare(TeamMemberVo t1, TeamMemberVo t2) {
                        //按组长排
                        int flag = t2.getIsLeader() - t1.getIsLeader();
                        //按职称排
                        if (flag == 0) {
                            flag = t1.getSort() - t2.getSort();
                        }
                        //按名字排
                        if (flag == 0) {
                            flag = t1.getName().compareTo(t2.getName());
                        }
                        return flag;
                    }
                });
                team.setTeamMemberList(teamMemberVoList);
                teams.add(team);
            }
            return teams;
        }
        return null;
    }

    /**
     * 查询未分组成员
     *
     * @param labId
     * @return
     */
    public List<TeamMemberVo> noTeam(Long labId) {
        Assert.isTrue(labId != null, "参数缺失！");
        //已分组成员的LabMemberId
        List<TeamMember> teamMembers = teamMemberService.selectAllTeamLabMemberId(labId);
        //此实验室所有成员的LabMemberId,name,imageUr和duty集合
        List<LabMemberInfo> labMemberInfos = teamService.selectLabMemberInfoByLabId(labId);

        Map<Integer, String> userDutyMap = dictService.getUserDutyMap();
        List<TeamMemberVo> noTeam = new ArrayList<TeamMemberVo>();
        if (labMemberInfos != null) {
            for (LabMemberInfo labMemberInfo : labMemberInfos) {
                boolean isNotTeam = true;
                if (teamMembers != null) {
                    for (TeamMember teamMember : teamMembers) {
                        if (labMemberInfo.getLabMemberId().equals(teamMember.getLabMemberId())) {
                            isNotTeam = false;
                        }
                    }
                    if (isNotTeam) {
                        TeamMemberVo teamMemberVo = new TeamMemberVo();
                        MyBeanUtils.copyProperties(labMemberInfo, teamMemberVo);
                        teamMemberVo.setDuty(StringUtils.isNotBlank(labMemberInfo.getDuty())?labMemberInfo.getDuty():"PI");
                        userDutyMap.forEach((k,v) -> {
                            if(v.equals(labMemberInfo.getDuty())){
                                teamMemberVo.setSort(k);
                            }
                        });
                        noTeam.add(teamMemberVo);
                    }
                }
            }
        }
        Collections.sort(noTeam, new Comparator<TeamMemberVo>() {
            @Override
            public int compare(TeamMemberVo t1, TeamMemberVo t2) {
                //按职称排
                int flag = t1.getSort() - t2.getSort();
                //按名字排
                if (flag == 0) {
                    flag = t1.getName().compareTo(t2.getName());
                }
                return flag;
            }
        });
        return noTeam;
    }

    /**
     * 删除团队
     *
     * @param teamId
     */
    public boolean deleteTeam(Long labId,Long teamId) {
        Assert.isTrue(teamId != null,"参数缺失！");
        Team team=teamService.selectOneByLabIdAndTeamId(labId,teamId);
        Assert.notNull(team,"该团队已被删除，请刷新界面。");
        Assert.isTrue(!labMemberService.isOwner(labId,team.getLeaderId()),"PI小组无法删除！");
        teamService.updateTeamIsDelete(teamId);
        teamMemberService.updateTeamMemberState(teamId);
        return true;
    }

    /**
     * 是否为组长或者PI
     *
     * @param labId
     * @param labMemberId
     * @return
     */
    public boolean isLeaderOrPi(Long labId,Long labMemberId) {
        Assert.isTrue(labId != null && labMemberId != null,"参数缺失！");
        List<TeamMember> leaders=teamMemberService.selectLeaderList(labId);
        List<Long> leaderMemberIds=leaders.stream().map(TeamMember::getLabMemberId).collect(Collectors.toList());
        boolean contains=leaderMemberIds.contains(labMemberId);
        boolean owner=labMemberService.isOwner(labId,labMemberId);
        return contains || owner;
    }

    /**
     * 成员获取组长
     *
     * @param labId
     * @param labMemberId
     * @return
     */
    public TeamMemberVo getLeaderOfTeamMember(Long labId,Long labMemberId) {
        Assert.isTrue(labId != null && labMemberId != null,"参数缺失！");
        TeamMember me=teamMemberService.selectOneByLabIdAndLabMemberId(labId,labMemberId);
        if(me != null){
            return teamMemberService.selectLeaderVo(me.getTeamId());
        }
        return null;
    }

    /**
     * 实验室成员加入小组
     * @param labMemberId
     * @param teamId
     * @return
     */
    public TeamMember entryTeam(Long labMemberId,Long teamId,Long labId) {

        Team piTeam=this.getPiTeam(labId);

        if(teamId!=null){

            if(piTeam!=null && piTeam.getId().equals(teamId)){
                return null;
            }else {

                LabMember labMemberU=labMemberService.selectById(labMemberId);
                Assert.notNull(labMemberU,"实验室成员不存在！");

                LabMember labMember = labMemberService.selectByLabIdAndUserId(labId,labMemberU.getUserId());

                Team team = teamService.selectById(teamId);
                Assert.notNull(team,"研究小组不存在！");
                Assert.isTrue(team.getLabId().equals(labId),"研究小组不属于该实验室！");
                Assert.isTrue(!labMemberService.isOwner(labId,team.getLeaderId()),"PI小组无法加入！");

                List<TeamMember> teamMembers=teamMemberService.selectListByTeamIdAndState(teamId,TeamMemberStateEnum.IN.getState());
                TeamMember exist=teamMembers.stream().filter(e -> e.getLabMemberId().equals(labMember.getId())).findFirst().orElse(null);
                if(exist==null){
                    TeamMember teamMember=new TeamMember();
                    teamMember.setLabId(labId);
                    teamMember.setIsLeader(BoolEnum.FALSE.getValue());
                    teamMember.setState(TeamMemberStateEnum.IN.getState());
                    teamMember.setTeamId(teamId);
                    teamMember.setLabMemberId(labMember.getId());

                    teamMemberService.insert(teamMember);
                    return teamMember;
                }
            }

        }
        return null;
    }

    /**
     * 初始化PI小组
     * 使用场景： (1)PI创建实验室成功 (2)成员创建实验室，邀请PI成功
     *
     * @return
     */
    public Team createOwnerTeam(Long labId,Long ownerId){
        Lab lab=labService.selectById(labId);
        Assert.notNull(lab,"实验室尚未创建！");

        Users users=usersService.selectUser(ownerId,UserEnum.State.NORMAL.getValue());
        Assert.notNull(users,"PI不存在！");

        LabMember labMember=labMemberService.selectByLabIdAndUserId(labId,ownerId);
        Assert.notNull(labMember,"PI成员未创建！");

        Team exist=teamService.selectOneByLeaderId(labMember.getId());
        Assert.isNull(exist,"PI研究小组已存在！");

        Team team=new Team();
        team.setLeaderId(labMember.getId());
        team.setName(String.format("%s的研究小组",users.getName()));
        team.setLabId(labId);

        teamService.insert(team);

        return team;
    }

    public Team getPiTeam(Long labId) {
        Lab lab=labService.selectById(labId);
        if(lab!=null){
            LabMember labMember=labMemberService.selectByLabIdAndUserId(labId,lab.getOwnerId());
            Assert.notNull(labMember,"PI成员不存在！");

            Team team=teamService.selectOneByLeaderId(labMember.getId());
            return team;
        }

        return null;

    }

    /**
     * PI小组编辑
     * @param id
     * @param name
     * @param userInfo
     */
    public void editPiTeam(Long id,String name,UserInfoVo userInfo) {
        Team team=teamService.selectById(id);
        Assert.notNull(team,String.format("ID为:%s的小组不存在！",id));

        Assert.isTrue(labMemberService.isOwner(userInfo.getLabId(),userInfo.getLabMemberId()),"您无权限进行此操作！");

        Team update=new Team();
        update.setName(name);
        update.setId(id);
        teamService.updateById(update);
    }
}
